package com.reran.geek.demo.Week01;


import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @description:
 * @author: Reran
 * @date: 2021/11/7
 */
public class ReraaanClassLoader extends ClassLoader {

    public static void main(String[] args)
            throws ClassNotFoundException, InstantiationException,
            IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        final String fileName = "Hello";

        ReraaanClassLoader reraaanClassLoader = new ReraaanClassLoader();
        Class<?> aClass = reraaanClassLoader.loadClass(fileName);
        Object helloObject = aClass.newInstance();

        final String methodName = "hello";
        Method method = aClass.getMethod(methodName);
        method.invoke(helloObject);


    }


    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {

        final String suffix = ".xlass";

        // 获取resource下的文件
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(name + suffix);
        if (Objects.isNull(resourceAsStream)) {
            throw new ClassNotFoundException(name);
        }
        try {
            int available = resourceAsStream.available();

            // inputStream转byte[]
            byte[] xlassByte = new byte[available];
            resourceAsStream.read(xlassByte);
            // xlass文件解码
            byte[] decodeByte = decodeXlass(xlassByte);
            // ClassLoader 加载字节码
            // 返回加载后的字节码
            return this.defineClass(name, decodeByte, 0, decodeByte.length);

        } catch (IOException e) {
            throw new ClassNotFoundException(name, e);
        } finally {
            if (Objects.nonNull(resourceAsStream)) {
                try {
                    resourceAsStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    private static final byte[] decodeXlass(byte[] xlassByteArray) {
        byte[] decodeByte = new byte[xlassByteArray.length];

        for (int i = xlassByteArray.length - 1; i >= 0; i--) {
            decodeByte[i] = (byte) (255 - xlassByteArray[i]);
        }

        return decodeByte;

    }

}
